package crystal.workshop.ui;

import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.beans.PropertyChangeSupport;
import java.util.ArrayList;
import java.util.Collection;

import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

import crystal.workshop.external.AtomEye;

import mujl.ui.DefaultSelectionModel;
import mujl.ui.JTableHideableColumns;

public class StructuresListTableUI extends JTableHideableColumns {

	/**
	 * 
	 */
	private static final long serialVersionUID = -4623666103618731032L;
	
	private static final String DEFAULT_SORT_COL = "Enthalpy";

	public enum Property {
		LIST_MODEL
	}
	
	protected StructuresListModel	strListModel;
	
	protected DefaultSelectionModel<Collection<StructureDataModel>> strSelectionModel;
	
	protected final ListController	controller = new ListController();
	
	protected transient PropertyChangeSupport propertyChange;
	
	// TODO Fix this
	protected final AtomEye atomEye = new AtomEye();
	
	class ListController implements ChangeListener, ListSelectionListener {
		
		// ChangeListener interface ////////////////////////////////////////////
		@Override
		public void stateChanged(final ChangeEvent evt) {
			// Check if the selection has changed
			if(evt.getSource() == StructuresListTableUI.this.getSelectionModel()) {
				selectionModelSelectionChanged();
			}
		}
		
		// ListSelectionListener interface ////////////////////////////////////
		@Override
	    public void valueChanged(ListSelectionEvent e) {
	        // If cell selection is enabled, both row and column change events are fired
	        if (e.getSource() == StructuresListTableUI.this.getSelectionModel()
	        		&& StructuresListTableUI.this.getRowSelectionAllowed()) {
	        	// Tell the list that the selection has changed and needs to be
	        	// updated
	        	tableUISelectionChanged();
	        }
	    }		
	};
	
	/**
	 * Return the structure list model.
	 * @return the structures list model.
	 */
	protected StructuresListModel getStructuresListModel() {
		return strListModel;
	}
	
	protected DefaultSelectionModel<Collection<StructureDataModel>> getStructureSelectionModel() {
		return strSelectionModel;
	}
	
	/**
	 * Set the the structure list model to a new value.
	 * @param newValue the new structure list model
	 */
	public void setStructureListModel(final StructuresListModel newValue) {
		if (strListModel != newValue) {
			try {
				final StructuresListModel oldValue = getStructuresListModel();
				/* Stop listening for events from the current object */
				if (strListModel != null) {
					//strListModel.removePropertyChangeListener(controller);
				}
				strListModel = newValue;
	
				/* Listen for events from the new object */
				if (strListModel != null) {
					//strListModel.addPropertyChangeListener(controller);
					setModel(new StructuresListModelTableAdapter(strListModel));
				}
				firePropertyChange(Property.LIST_MODEL, oldValue, newValue);
			} catch (Exception e) {
			}
		};
	}
	
	public void setStructureSelectionModel(
			final DefaultSelectionModel<Collection<StructureDataModel>> newValue)
	{
		if(strSelectionModel != newValue) {
			//final DefaultSelectionModel<Collection<StructureDataModel>> oldValue =
			//	getStructureSelectionModel();
			if(strSelectionModel != null) {
				strSelectionModel.removeChangeListener(controller);
			}
			strSelectionModel = newValue;
			
			// Listen for events from the new object
			if(strSelectionModel != null) {
				strSelectionModel.addChangeListener(controller);
			}
		}
	}
	
	/**
	 * Accessor for the propertyChange field.
	 * @return the PropertyChangeSupport instance
	 */
	protected PropertyChangeSupport getPropertyChange() {
		if (propertyChange == null) {
			propertyChange = new java.beans.PropertyChangeSupport(this);
		};
		return propertyChange;
	}
	
	protected JPopupMenu getPopupShowColumns() {
		if(jPopupShowColumn == null) {
			jPopupShowColumn = new JPopupMenu();
		}
		return jPopupShowColumn;
	}
	
	public StructuresListTableUI() {
		super();
		
		// Make it so that row selection is possible
		setRowSelectionAllowed(true);
		setAutoCreateRowSorter(true);
		setShowHorizontalLines(false);
		setShowVerticalLines(true);
		
		initialise();
	}
	
	/**
	 * Initialise the class.
	 */
	private void initialise() {
		try {
			setName("StructuresListTableUI");
			//getTableHeader().addMouseListener(controller);
			
			initConnections();
		} catch (java.lang.Throwable ivjExc) {
		}
	}
	
	private void initConnections() {
		getSelectionModel().addListSelectionListener(controller);
	}
	
	/**
	 * The structure selected in the UI has changed. 
	 */
	private void tableUISelectionChanged() {
		final int selectedRows[] = getSelectedRows();
		final ArrayList<StructureDataModel> selection =
			new ArrayList<StructureDataModel>(selectedRows.length);
		
		// Find the StructureDataModels for the currently selected structures
		StructureDataModel str = null;
		for( int i : getSelectedRows() ) {
			str = getStructuresListModel().find(getValueAt(i, 0).toString());
			if(str != null ) {
				selection.add(str);
				//atomEye.launchWithResFile(str.getCustomName());
			}
		}
		if(selection.size() > 0)
			getStructureSelectionModel().setSelection(selection);
	}
	
	/**
	 * Show the popup allowing column selection.
	 * @param e the mouse event that resulted in this call
	 */
	/*protected void showColumnPopup(final MouseEvent e) {
		final JPopupMenu popup = getPopupShowColumns();
		popup.removeAll();
		for(int i = 0; i < getColumnCount(); ++i) {
			popup.add(new JMenuItem(getColumnName(i)));
		}
		popup.show(getTableHeader(), e.getX(), e.getY());
	}*/
	
	/**
	 * The selection has been changed in the selection model. Update the UI to
	 * reflect this.
	 */
	private void selectionModelSelectionChanged() {
		for( StructureDataModel str : getStructureSelectionModel().getSelection() ) {
			//if( str.getCustomName().equals(arg0) )
		}
	}
	
	/**
	 * The firePropertyChange method was generated to support the propertyChange field.
	 * @param propertyName Property that is changing
	 * @param oldValue Object
	 * @param newValue Object
	 */
	public void firePropertyChange(final Property property, java.lang.Object oldValue, java.lang.Object newValue) {
		getPropertyChange().firePropertyChange(property.toString(), oldValue, newValue);
	}
}
